package org.aman.generator.util;

import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.StringTokenizer;

import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;

/**
 * @desc <p></p>
 * @author DaiJiangGuo
 * @date 2015年5月14日上午11:36:46
 */
public class JavaFileUtil {

    private List<JavaFileLine> lines = new ArrayList<JavaFileLine>();
    private List<String> importList = new ArrayList<String>();
    private List<String> fieldList = new ArrayList<String>();
    private List<String> methodList = new ArrayList<String>();

    private File javaFile;
    private FullyQualifiedJavaType type;
    static boolean parseClass = false;

    /**
     * 创建一个新的实例JavaFileUtil.
     * @throws FileNotFoundException
     */
    public JavaFileUtil(File javaFile, FullyQualifiedJavaType type) throws FileNotFoundException {
        this.javaFile = javaFile;
        this.type = type;
        loadJavaFileLine();

//        for(JavaFileLine line : lines){
//            System.out.println(line.isBlank() + "\t" + line.isWholeJdocComment() + "\t" + line.isWholeBlockComment()
//                    + "\t" + line.isWholeLineComment() + "\t" + line.getContent());
//        }
    }


    /**
     * @author DaiJiangGuo
     * @data 2015年5月14日 上午11:45:01
     * @param javaFile
     * @return
     * @throws FileNotFoundException
     */
    private void loadJavaFileLine() throws FileNotFoundException {
        Scanner sc = new Scanner(javaFile);
        int lineCnt = 1;
        boolean jdoc = false;
        boolean block = false;
        while(sc.hasNextLine()){
            String line = sc.nextLine();
            JavaFileLine jl = new JavaFileLine(lineCnt++, line);
            lines.add(jl);

            String lineTrim = line.trim();
            if (lineTrim.matches("\\s*")) {
                jl.setBlank(true);
            }

            if (!jdoc && !block && lineTrim.startsWith("//")) {
                jl.setWholeLineComment(true);
                jl.setWholeJdocComment(false);
                jl.setWholeBlockComment(false);
                continue;
            } else {
                jl.setWholeLineComment(false);
            }

            if (jdoc || lineTrim.startsWith("/**")) {
                if (!lineTrim.contains("*/") || lineTrim.indexOf("*/") == lineTrim.length() - 2) {
                    jl.setWholeLineComment(false);
                    jl.setWholeJdocComment(true);
                    jl.setWholeBlockComment(false);
                } else {
                    jl.setWholeJdocComment(false);
                }
            } else {
                jl.setWholeJdocComment(false);
            }
            if (block || (lineTrim.startsWith("/*") && !lineTrim.startsWith("/**"))) {
                if (!lineTrim.contains("*/") || lineTrim.indexOf("*/") == lineTrim.length() - 2) {
                    jl.setWholeLineComment(false);
                    jl.setWholeJdocComment(false);
                    jl.setWholeBlockComment(true);
                } else {
                    jl.setWholeBlockComment(false);
                }
            } else {
                jl.setWholeBlockComment(false);
            }
            lineTrim = lineTrim.replaceAll("\".*\"", "\"\"");

            for(int i=0;i<lineTrim.length();i++){
                if(jdoc && block){//不存在
                }else if(jdoc && !block){
                    if(lineTrim.charAt(i) == '*' && (i+1<lineTrim.length()) && lineTrim.charAt(i+1) == '/'){
                        jdoc = false;
                        i++;
                    }
                }else if(!jdoc && block){
                    if(lineTrim.charAt(i) == '*' && (i+1<lineTrim.length()) && lineTrim.charAt(i+1) == '/'){
                        block = false;
                        i++;
                    }
                }else if(!jdoc && !block){
                    if(lineTrim.charAt(i) == '/' && (i+1<lineTrim.length()) && lineTrim.charAt(i+1) == '/' ){
                        break;
                    }
                    if(lineTrim.charAt(i) == '/' && (i+1<lineTrim.length()) && lineTrim.charAt(i+1) == '*'){
                        block = true;
                        i++;
                        if((i+1<lineTrim.length()) && lineTrim.charAt(i+1) == '*'){
                            jdoc = true;
                            block = false;
                            i++;
                        }
                    }
                }
            }
        }
        sc.close();
    }

    public List<JavaFileLine> parse() throws FileNotFoundException{

        if(lines == null || lines.isEmpty()){
            loadJavaFileLine();
        }

        String java = " ";
        for(int i=0;i<lines.size();i++){
            JavaFileLine line = lines.get(i);
            String content = getContent(line);
            if(line.isBlank() || line.isWholeBlockComment() || line.isWholeJdocComment() || line.isWholeLineComment()){
                //空行 注释行 不处理
            }else{
                boolean over = false;
                int level = 0;
                int k = 0;
                while(!over){
                    int overIndex = 0;
                    for(int j=0;j<content.length();j++){
                        if(content.charAt(j) == ';' && level <= 0){
                            over = true;
                        }else if(content.charAt(j) == '{'){
                            level++;
                        }else if(content.charAt(j) == '}' && --level <= 0){
                            over = true;
                        }

                        if(over){
                            overIndex = j;
                            break;
                        }
                    }

                    if(!over){//语句未结束
                        java += content + " ";//语句加上

                        if(!parseClass){//语句没有解析到类 语句没有结束
                            if(java.matches("(^|.*\\s)class(\\s.*|$)")){//包含class
                                if(java.contains("{")){
                                    over = true;
                                }
                            }
                        }else if("}".equals(java.trim())){
                            over = true;
                        }
                        if(!over){
                            k = k+1;
                            if(i+k <lines.size()){
                                content = getContent(lines.get(i+k));
                            }else{
                                break;
                            }
                        }
                    }else{
                        java += content.substring(0, overIndex+1);
                        if(overIndex+1<content.length()){
                            String other = content.substring(overIndex+1);
                            if(";".equals(other.trim())||other.trim().startsWith("while")){// private int[] sd = {}; do{}while();

                            }else{//private int a=1; private int b=2;
                                line.setMulti(true);
                            }
                        }
                    }
                }//得到语句 或者文件结束 
                if(over){
                    JavaStatement e = getJavaElement(java);
                    setLineType(i, i+k, e);

                    if("class".equals(e.getElementType())){//解析下一行
                        i = i+k;
                    }else{
                        i = i+k;
                    }
                    k = 0;
                    java = " ";
                }
            }
        }
//        for(int i=0;i<lines.size();i++){
//            JavaFileLine line = lines.get(i);
//            System.out.println(//line.isBlank() + "\t" + line.isWholeJdocComment() + "\t" + line.isWholeBlockComment()
//                    //+ "\t" + line.isWholeLineComment() +"\t"+
//                    line.getType() + "\t" + line.getForObj()+ "\t" + line.getContent());
//        }
        return lines;
    }
    /**
     * @author DaiJiangGuo
     * @data 2015年5月14日 下午5:49:45
     * @param i
     * @param k
     */
    private void setLineType(int startLine, int endLine, JavaStatement e) {

        String et = e.getElementType();

        String ef = e.getForObj();

        for(int i=startLine;i<=endLine;i++){
            lines.get(i).setType(et);
            if(ef != null && !"".equals(ef)){
                lines.get(i).setForObj(ef);
            }
        }
        for(int i = startLine-1;i>=0;i--){
            String t = lines.get(i).getType();
            if(t == null || "".equals(t)){
                lines.get(i).setType(et);
                if(ef != null && !"".equals(ef)){
                    lines.get(i).setForObj(ef);
                }
            } else {
                break;
            }
        }

    }

    public static void main(String[] args) throws FileNotFoundException {
        new JavaFileUtil(new File("D:\\workspace\\testgen\\gen\\com\\flow\\entity\\Banner.java"),
                new FullyQualifiedJavaType("org.aman.generator.util.JavaLine")).parse();

//        System.out.println("package s".matches("(^|.*\\s)package(\\s.*|$)"));
//        getJavaElement("private int lineNo;");

    }
    private JavaStatement getJavaElement(String java){
        JavaStatement s = getJavaElement1(java);
        //System.out.println(s.getElementType()+"\t"+s.getForObj() + "\t"+java);
        return s;
    }

    /**
     * @author DaiJiangGuo
     * @data 2015年5月14日 下午4:21:03
     * @param java
     * @return
     */
    private JavaStatement getJavaElement1(String java) {//private int lineNo;
        if("}".equals(java.trim())){
            parseClass = false;
            return new JavaStatement("class");
        }

        java = java.replace("\\s+", " ");

        if(java.matches("(^|.*\\s)package(\\s.*|$)")){
            return new JavaStatement("package");
        }else if(java.matches("(^|.*\\s)import(\\s.*|$)*")){
            String importString = java.replace("import", "").replace(";", "").replaceAll("\\s+", "");
            importList.add(importString);
            return new JavaStatement("import", importString);
        }else if(java.matches("(^|.*\\s)class(\\s.*|$)")){
            if(!parseClass){
                parseClass = true;
                return new JavaStatement("class");
            }
            return new JavaStatement("innerClass");
        }else if(java.matches("(^|.*\\s)interface(\\s.*|$)")){
            return new JavaStatement("interface");
        }else if(java.matches("(^|.*\\s)enum(\\s.*|$)")){
            return parseClass ? new JavaStatement("innerEnum") : new JavaStatement("enum");
        }else{
            java = java.replace("public", "").replace("private", "").replace("protect", "").replace("static", "")
                    .replace("final", "").replace("synchronized", "").replaceAll("<.*>", "");

            if(java.trim().startsWith("{")){
                return new JavaStatement("block");
            }
            String firstWord = null;
            String secondWord = null;
            String threeStart = null;
            StringTokenizer st = new StringTokenizer(java, "= (;", true);
            while(st.hasMoreTokens()){
                String t = st.nextToken();
                if("".equals(t.trim())){
                    continue;
                }
                if(firstWord == null){
                    firstWord = t;
                    continue;
                }
                if(secondWord == null){
                    secondWord = t;
                    continue;
                }
                if(threeStart == null){
                    threeStart = t;
                    break;
                }
            }
            if(firstWord.equals(type.getShortName()) && secondWord.startsWith("(") ){
                methodList.add(firstWord);
                return new JavaStatement("method", firstWord);
            }

            if(threeStart.startsWith("=") || threeStart.startsWith(";")){
                fieldList.add(secondWord);
                return new JavaStatement("field", secondWord);
            }else if(threeStart.startsWith("(")){
                methodList.add(secondWord);
                return new JavaStatement("method", secondWord);
            }
        }
        return null;
    }

    /**
     * @author DaiJiangGuo
     * @data 2015年5月14日 下午4:09:24
     * @param line
     * @return
     */
    private String getContent(JavaFileLine line) {
        String content = line.getContent().trim();
        content = content.replaceAll("\".*\"", "\"\"")
                .replaceAll("'.*'", "''")
                .replaceAll("//.*", "")
                .replaceAll("/\\*.*\\*/", "")
                .replaceAll(".*\\*/", "")
                .replaceAll("/\\*", "");

        if(content.contains("@")){//去掉注解
            content = content.replaceAll("@\\s+", "@");
            content = content.replaceAll("@[^\\s(]+", "@");
            content = content.replaceAll("@\\(.*\\)", "@");
            content = content.replaceAll("@\\s+", "@");
            content = content.replace("@", "");
            
            
            content = content.replaceAll("@\\s+", "@").replaceAll("@[^\\s]+", "@")
                    .replaceAll("@\\s+", "@").replaceAll("@\\(.*\\)", "@")
                    .replace("@", "");
        }
        return content;
    }

    public Map<String, Integer> getAddColumnInfo(){
        Integer lastImportLine = null;
        Integer lastFieldLine = null;
        Integer lastMethodLine = null;
        Integer classStartLine = null;
        Integer classBodyStartLine = null;
        for(int i=0;i<lines.size();i++){
            JavaFileLine line = lines.get(i);
            if("import".equals(line.getType()) ){
                lastImportLine = i;
            }
            if("field".equals(line.getType()) ){
                lastFieldLine = i;
            }
            if("method".equals(line.getType()) ){
                lastMethodLine = i;
            }
            if("class".equals(line.getType()) ){
                if(classStartLine == null){
                    classStartLine = i;
                }
            }
            if (classStartLine != null && !"class".equals(line.getType())) {
                classBodyStartLine = i;
            }
        }
        if(lastImportLine == null){
            lastImportLine = classStartLine - 1;
        }
        if(lastFieldLine == null){
            lastFieldLine = classBodyStartLine - 1;
        }
        if(lastMethodLine == null){
            lastMethodLine = lastFieldLine;
        }

        Map<String, Integer> map = new HashMap<String, Integer>();
        map.put("lastImportLine", lastImportLine);
        map.put("lastFieldLine", lastFieldLine);
        map.put("lastMethodLine", lastMethodLine);

        return map;
    }


    public List<String> getImportList() {
        return importList;
    }


    public void setImportList(List<String> importList) {
        this.importList = importList;
    }


    public List<String> getFieldList() {
        return fieldList;
    }


    public void setFieldList(List<String> fieldList) {
        this.fieldList = fieldList;
    }


    public List<String> getMethodList() {
        return methodList;
    }


    public void setMethodList(List<String> methodList) {
        this.methodList = methodList;
    }


    public List<JavaFileLine> getLines() {
        return lines;
    }


    public void setLines(List<JavaFileLine> lines) {
        this.lines = lines;
    }

}
